package com.yuebook.smartrpc.framework.provider;

import com.yuebook.smartrpc.framework.helper.PropertyConfigHelper;
import com.yuebook.smartrpc.framework.model.SmartRpcRequest;
import com.yuebook.smartrpc.framework.serialization.NettyDecodeHandler;
import com.yuebook.smartrpc.framework.serialization.NettyEncodeHandler;
import com.yuebook.smartrpc.framework.serialization.common.SerializerType;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import java.net.InetSocketAddress;

/**
 * @author honglei
 * @date 2018/11/19 下午9:06
 */
public class NettyServer {

    private static NettyServer nettyServer = new NettyServer();

    private Channel channel;

    private EventLoopGroup boosGroup;

    private EventLoopGroup workerGroup;

    private SerializerType serializerType = PropertyConfigHelper.getSerializeType();

    private NettyServer(){}

    public void start(final int port) {
        synchronized (NettyServer.class) {
            if (boosGroup != null || workerGroup != null) {
                return;
            }
            boosGroup = new NioEventLoopGroup();
            workerGroup = new NioEventLoopGroup();
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            serverBootstrap.group(boosGroup, workerGroup)
                .channel(NioServerSocketChannel.class)
                .localAddress(new InetSocketAddress(port))
                .option(ChannelOption.SO_BACKLOG, 1024)
                .childOption(ChannelOption.TCP_NODELAY, true)
                .childOption(ChannelOption.SO_KEEPALIVE, true)
                .handler(new LoggingHandler(LogLevel.INFO))
                .childHandler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel socketChannel) throws Exception {
                        socketChannel.pipeline().addLast(new NettyDecodeHandler(SmartRpcRequest.class, serializerType));
                        socketChannel.pipeline().addLast(new NettyEncodeHandler(serializerType));
                        socketChannel.pipeline().addLast(new NettyServerInvokeHandler());
                    }
                });
            try {
                channel = serverBootstrap.bind().sync().channel();
            } catch (Exception e) {
                e.printStackTrace();
            }

        }
    }

    public void stop() {
        if (channel == null) {
            throw new RuntimeException("channel is null");
        }
        try {
            boosGroup.shutdownGracefully().sync();
            workerGroup.shutdownGracefully().sync();
            channel.close().sync();
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    public static NettyServer singleton() {
        return nettyServer;
    }
}
